#include <iostream>

#include "codec.h"
#include "dispatcher.h"
#include "query.pb.h"
#include "xlcomm/net/tcp_client.h"

using namespace xlcomm;

class QueryClient {
 public:
  QueryClient(net::EventLoop* loop, const net::InetAddress& listen_addr)
      : loop_(loop),
        client_(loop, listen_addr, "QueryClient"),
        dispatcher_(),
        codec_(std::bind(&ProtobufDispatcher::OnProtobufMessage, &dispatcher_,
                         _1, _2, _3)) {
    client_.set_connect_callback(
        std::bind(&QueryClient::OnConnection, this, _1));
    client_.set_disconnect_callback(
        std::bind(&QueryClient::OnConnection, this, _1));
    client_.set_message_callback(
        std::bind(&ProtobufCodec::OnMessage, &codec_, _1, _2, _3));
    dispatcher_.RegisterMessageCallback<Answer>(
        std::bind(&QueryClient::OnAnswer, this, _1, _2, _3));
  }

  void Connect() { client_.Connect(); }

 private:
  using ConnectionList = std::set<net::TcpConnectionPtr>;

  void OnConnection(const net::TcpConnectionPtr& conn) {
    if (conn->IsConnected()) {
      conn_ = conn;
      Query query;
      query.set_id(2300);
      query.set_questioner("virtual-pc");
      query.set_question("What's your name?");
      codec_.Send<Query>(conn, query);
    } else {
      conn_.reset();
    }
  }

  void OnAnswer(const net::TcpConnectionPtr& conn,
                const std::shared_ptr<Answer>& answer, Timestamp recv_time) {
    std::cout << "QueryClient::OnAnswer----";
    std::string type_name = answer->GetTypeName();
    std::cout << " type_name:" << type_name;

    XLCOMM_ASSERT(strcmp(type_name.c_str(), "xlcomm.Answer") == 0);
    std::cout << " id:" << answer->id()
              << " questioner:" << answer->questioner()
              << " answerer:" << answer->answerer()
              << " slotion:" << answer->slotion() << std::endl;

    Empty empty;
    empty.set_id(2300);
    codec_.Send<Empty>(conn, empty);
  }

  net::EventLoop* loop_;
  net::TcpClient client_;
  net::TcpConnectionPtr conn_;
  ProtobufDispatcher dispatcher_;
  ProtobufCodec codec_;
};

int main() {
  net::EventLoop loop;
  QueryClient client(&loop, net::InetAddress(30002, "127.0.0.1"));
  client.Connect();
  loop.Loop();
  return 0;
}